import numpy as np
import os
# local modules
import load
load = reload( load )
import abaqus_functions
abaqus_functions = reload( abaqus_functions )
import conecyl._plot
conecyl._plot = reload( conecyl._plot )
import conecyl._read_outputs
conecyl._read_outputs = reload( conecyl._read_outputs )
# abaqus functions
from abaqus import *
from regionToolset import Region
# local constants
from constants import *
# abaqus constants
from abaqusConstants import *
#
class ConeCyl(object):
    
    def __init__(self):
        self.index = 0
        self.name = ''
        self.jobname = ''
        self.rebuilt = False
        # geometry related
        self.r = None
        self.r2 = None
        self.h = None
        self.alphadeg = 0.
        self.alpharad = None
        self.betadeg = 0.
        self.betarad = None
        self.holes = []
        self.cutplanes = []
        self.cross_sections = []
        self.meridians = []
        # material related
        self.laminaprop = None
        self.allowables = None
        # property related
        self.laminate_t = None
        self.plyt = None
        self.stack = []
        self.laminate_obj = None
        # load related
        self.axialdispl = None
        self.axialInclude = True
        self.separate_load_steps = True
        self.ploadconf = load.PLoadConf()
        self.ploadconf.conecyl = self
        # mesh related
        self.numel_r = None
        self.numel_h = None
        self.numel_hr_ratio = None
        self.elem_type = 'S4R5'
        self.elsize_r = None
        self.elsize_h = None
        self.meshname = ''
        # analysis related
        self.imperfection_activate        = False
        self.imperfection_filename        = ''
        self.imperfection_step_num        = ''
        self.imperfection_buckling_modes  = []
        self.imperfection_scaling_factors = []
        self.using_lam_parameters = False
        self.artificial_damping = True
        self.minInc = None
        self.maxInc = None
        self.stabilizationMagnitude = None
        self.adaptiveDampingRatio = False
        self.maxNumInc = None
        self.step1Name = ''
        self.step2Name = ''
        # file management related
        self.tmp_dir = r'C:\Temp\abaqus'
        self.study = None
        self.study_dir = r'C:\Temp\abaqus'
        self.output_dir = r'C:\Temp\abaqus\outputs'
        #ABAQUS objects
        self.mdb = None
        self.mod = None
        self.part = None
        self.job = None
        self.xyplots = []
        self.nodes = {}
        self.faces = []
        self.part_edges = []
        self.inst_edges = []
        #OUTPUTS
        self.jobwalltime = None
        self.zdisp = []
        self.zload = []
        self.stress_min_num     = {}
        self.stress_min_ms      = {}
        self.stress_min_pos_num = {}
        self.stress_max_num     = {}
        self.stress_max_ms      = {}
        self.stress_max_pos_num = {}
        self.hashin_max_num     = {}
        self.hashin_max_ms      = {}
        self.hashin_max_pos_num = {}
        self.output_requests = ('U', 'NFORC') 
        self.request_stress_output = False
        #self.output_requests = ( 'U', 'RF', 'RT', 'CF', 'SF', 'NFORC',
        #                         'E','EE','IE' )
    
    def fromDB(self):
        import conecylDB
        conecylDB = reload( conecylDB )
        if self.name in conecylDB.conecylDB.keys():
            conecyl = conecylDB.conecylDB[ self.name ]
            for k,v in conecyl.iteritems():
                if k == 'pload':
                    pload = load.PLoad(theta=0., pt=0.5, pltotal=v)
                    pload.ploadconf = self.ploadconf
                    setattr( self.ploadconf, 'ploads', [ pload ] )
                else:
                    setattr( self, k, v )
            self.rebuild()
        else:
            print 'WARNING - %s is not in database conecylDB' % self.name


    def rebuild(self):
        import conecyl._rebuild
        conecyl._rebuild = reload( conecyl._rebuild )
        conecyl._rebuild.rebuild( self )

    def r_z_from_ppoint( self, ppoint=0.5):
        r = self.r + (self.r2 - self.r)*ppoint
        z = self.h * ppoint
        return r, z 

    def add_hole( self ):
        pass

    def find_edge( self, theta ):
        for edge in self.edges:
            if abs( edge.theta - theta ) < TOL:
                return edge

    def step_name( self, step_num ):
        if step_num == 1:
            return self.step1Name
        else:
            return self.step2Name

    def create_model( self ):
        import conecyl._create_model
        conecyl._create_model = reload( conecyl._create_model )
        conecyl._create_model.create_model( self )

    def write_job( self, submit=False ):
        import conecyl._write_job
        conecyl._write_job = reload( conecyl._write_job )
        conecyl._write_job.write_job( self, submit )

    def read_walltime( self ):
        #FIXME why the error?? remove try / except
        try:
            tmppath = os.path.join( self.output_dir, self.jobname + '.msg' )
            tmp = open( tmppath, 'r' )
            lines = tmp.readlines()
            a,a,a,a,w = lines[-1].split()
            self.jobwalltime = float(w) 
            tmp.close()
        except:
            self.jobwalltime = None

    def attach_results( self ):
        odbname = os.path.join( self.output_dir, self.jobname + '.odb' )
        if not os.path.isfile( odbname ): 
            print 'WARNING - result was not found'
            return False
        import visualization
        import __main__
        if not odbname in __main__.session.odbs.keys():
            return visualization.openOdb( odbname )
        else:
            return __main__.session.odbs[ odbname ]

    def detach_results( self, odb ):
        import visualization
        visualization.closeOdb( odb ) 

    def read_and_map_nodes( self ):
        import conecyl._read_and_map_nodes
        conecyl._read_and_map_nodes = reload( conecyl._read_and_map_nodes )
        conecyl._read_and_map_nodes.read_and_map_nodes( self )

    def read_outputs( self, last_frame = False,
                            last_cross_section = True ):
        conecyl._read_outputs.read_outputs( self, 
                                            last_frame,
                                            last_cross_section )

    def read_outputs_cross_section( self, odb,
                                    cross_section_index = -1,
                                    last_frame = False ):
        conecyl._read_outputs.read_outputs_cross_section(
            self, odb, cross_section_index, last_frame )

    def read_axial_load_displ( self, step_num ):
        #
        step_name = self.step_name( step_num )
        nodes = self.cross_sections[-1].nodes
        frmlen = len( nodes[-1].fz[step_name] )
        self.zdisp = [0. for i in range(frmlen)]
        self.zload = [0. for i in range(frmlen)]
        for i in range( frmlen ):
            for node in nodes:
                self.zload[ i ] += node.fz[ step_name ][ i ]
            self.zdisp[ i ] = node.dz[ step_name ][ i ]

    def plot_displacements( self, step_num ):
        conecyl._plot.plot_displacements( self, step_num )

    def plot_forces( self, step_num = 2, along_edge = False ):
        conecyl._plot.plot_forces( self, step_num, along_edge )

    def plot_stress_analysis( self, disp_force_frame = 'DISP' ):
        conecyl._plot.plot_stress_analysis( self, disp_force_frame )
        self.plot_forces()
        abaqus_functions.configure_session()

    def plot_xy( self, xs, ys, name = 'default_plot',
                 xValuesLabel = 'x axis', yValuesLabel = 'y_axis',
                 legendLabel = '' ):
        conecyl._plot.plot_xy( self, xs, ys, name,
                               xValuesLabel, yValuesLabel, legendLabel )

    def read_ehr( self ):
        self.read_displacements( step_num = 1 )
        for pload in self.ploadconf.ploads:
            pload.calc_ehr_and_displ()

    def check_completed( self, wait = False ):
        if not self.rebuilt:
            self.rebuild()
        tmp = os.path.join( self.output_dir, self.jobname + '.msg' )
        if wait == True:
            print ('Waiting for job completion...')
        while True:
            if os.path.isfile( tmp ):
                tmpfile = open( tmp, 'r' )
                lines = tmpfile.readlines()
                tmpfile.close()
                if len(lines) == 0:
                    continue
                if lines[-1].find('       WALLCLOCK') > -1:
                    #print 'DEBUG - last .msg line', lines[-1]
                    print 'RUN COMPLETED for model %s' % self.jobname
                    return True
                elif not wait:
                    print 'RUN NOT COMPLETED for model %s' % self.jobname
                    return False
            elif not wait:
                print 'Job results not found for model %s' % self.jobname
                print '\t' + tmp
                return False
            if wait:
                import time
                time.sleep(5)

    def stress_analysis(  self, frames=None,
                          MSlimits=[0.0,0.2,0.5], frame_indexes=[] ):
        import conecyl._stress_analysis
        conecyl._stress_analysis = reload( conecyl._stress_analysis )
        conecyl._stress_analysis.calc_frames( self, frames,
                                              MSlimits, frame_indexes )
        self.plot_stress_analysis()

    def create_hole( self, coord=(), dh=None ):
        """
            coord   cylindrical coordinates (theta, z)
                    theta in degrees, measured from the
                    first perturbation load axis
            dh      the float number for the hole diameter
        """
        hole = hole.Hole( coord, dh ) 
        hole.conecyl = self
        hole.create()
        self.holes.append( hole )

